const execSync = require("child_process").execSync; //同步子进程
function getDate(time = "") {
  let date = "";
  if (time) {
    date = new Date(time);
  } else {
    date = new Date();
  }
  let y = date.getFullYear();
  let M = date.getMonth() + 1;
  let d = date.getDate();
  let h = date.getHours();
  let m = date.getMinutes();
  return `${y}年${M}月${d}日${h}时${m}分`;
}
function getDescriptionValue(value, type = "process") {
  if (type === "process") {
    return value ?? "--";
  } else if (type === "date") {
    let string = "";
    try {
      string = getDate(execSync(value)?.toString().trim());
      execSync(value)?.toString().trim();
    } catch (err) {
      string = "--";
    }
    return string;
  } else {
    let string = "";
    try {
      string = execSync(value)?.toString().trim();
    } catch (err) {
      string = "--";
    }
    return string;
  }
}
class buildInfoPlugin {
  constructor(options = {}) {
    this.options = {
      // 命令名称
      name: options?.name ?? "buildInfo",
      // 是否立即输出
      immediate: options?.immediate ?? false,
      // 是否保留预设值
      preset: options?.preset ?? true,
      // 自定义要展示的数据
      consoleList: options?.consoleList ?? [],
    };
  }
  consoleList() {
    // 预设的consoleList
    let presetConsoleList = [
      {
        description: "提交时间",
        value: getDescriptionValue("git show -s --format=%cd", "date"),
        mode: "development",
      },
      {
        description: "构建时间",
        value: getDate(),
        mode: "production",
      },
      {
        description: "提交人员",
        value: getDescriptionValue("git show -s --format=%cn", "git"),
        mode: "development",
      },
      {
        description: "构建人员",
        value: getDescriptionValue(process.env?.TRIGGER_USER_NAME),
        mode: "production",
      },
      {
        description: "提交邮箱",
        value: getDescriptionValue("git show -s --format=%ce", "git"),
        mode: "development",
      },
      {
        description: "仓库名称",
        value: getDescriptionValue(process.env?.DEPOT_NAME),
        mode: "production",
      },
      {
        description: "代码分支",
        value: getDescriptionValue("git symbolic-ref --short -q HEAD","git"),
        mode: "development",
      },
      {
        description: "代码分支",
        value: getDescriptionValue(process.env?.GIT_BRANCH),
        mode: "production",
      },
      {
        description: "代码版本",
        value: getDescriptionValue('git show -s --format=%h',"git"),
        mode: "development",
      },
      {
        description: "代码版本",
        value: getDescriptionValue(process.env?.GIT_COMMIT_SHORT),
        mode: "production",
      },
      {
        description: "提交说明",
        value: getDescriptionValue('git show -s --format=%s',"git"),
        mode: "development",
      },
      {
        description: "镜像版本",
        value: getDescriptionValue(process.env?.CODING_DOCKER_IMAGE_NAME),
        mode: "production",
      },
    ];
    // 用户输入的consoleList
    let userConsoleList = this.options.consoleList;
    if (!Array.isArray(userConsoleList)) {
      userConsoleList = [];
    } else {
      userConsoleList =
        userConsoleList
          ?.filter((res) => res.description)
          ?.map((res) => {
            return {
              description: res.description,
              value: res?.value || "--",
              mode: res?.mode || "production",
            };
          }) || [];
    }
    // 需要生成的consoleList
    let consoleList = [];
    if (this.options.preset) {
      consoleList = [...presetConsoleList, ...userConsoleList];
    } else {
      if (userConsoleList.length === 0) {
        consoleList = [
          {
            description: "异常提示",
            value: "无可输出的信息！请检查配置或将preset设置为true",
            mode: "development",
          },
          {
            description: "异常提示",
            value: "无可输出的信息！请检查配置或将preset设置为true",
            mode: "production",
          },
        ];
      } else {
        consoleList = userConsoleList;
      }
    }
    // 根据不同环境进行筛选
    const consoleArray =
      consoleList
        ?.filter((res) => res.mode === process.env.NODE_ENV)
        ?.map((res) => {
          return {
            description: this.encode(res.description),
            value: this.encode(res.value),
          };
        }) || [];
    return JSON.stringify(consoleArray);
  }
  encode(str = "") {
    if (!str) return "";
    let r = "";
    for (let i = 0; i < str.length; i++) {
      r += str.charCodeAt(i) + ",";
    }
    return r;
  }
  getConsoleStr() {
    return "`%c${decode(description)}%c${decode(value)}`";
  }
  developmentTip() {
    if (process.env.NODE_ENV === "development" && this.options.preset) {
      let description = `const description = '${this.encode("提示信息")}';\n`
      let value = `const value = '${this.encode("当前打印信息基于本地git提交历史，非coding构建信息！")}';\n`
      let console = 'console.log(`%c${decode(description)}%c${decode(value)}`,"background:#c00 ; padding: 2px 0 2px 5px; border-radius: 3px 0 0 3px;  color: #fff","background:#f56c6c; padding: 2px 0 2px 5px; border-radius: 0 3px 3px 0;  color: #fff")';
      return description + value + console
    } else {
      return "";
    }
  }
  jsContent() {
    return `(function(window){
  function decode(str = ""){
    if(!str) return ""
    let arr = str.split(",");
    let r = "";
    for (let i = 0; i < arr.length; i++){
      r += String.fromCharCode(parseInt(arr[i]));
    }
    return r;
  }
  function log (description, value) {
    console.log(
      ${this.getConsoleStr()},
      "background:#35495e; padding: 2px 0 2px 5px; border-radius: 3px 0 0 3px;  color: #fff",
      "background:#41b883; padding: 2px 0 2px 5px; border-radius: 0 3px 3px 0;  color: #fff",
    )
  }
  window.BuildInfoConsoleList = ${this.consoleList()} || []
  if(${this.options.immediate}){
    ${this.developmentTip()}
    BuildInfoConsoleList.forEach(res=>{
      log (res.description, res.value) 
    })
  }
  Object.defineProperty(window, '${this.options.name}', {
    get: function() {
      if(BuildInfoConsoleList.length === 0){
        return console.log("暂无相关信息！")
      }
      console.clear();
      ${this.developmentTip()}
      BuildInfoConsoleList.forEach(res=>{
        log (res.description, res.value) 
      })
    }
  })
})(window)`;
  }
  apply(compiler) {
    compiler.hooks.emit.tap("buildInfoPlugin", (compilation) => {
      // 获取html及js路径信息
      const jsAssets = Object.keys(compilation.assets).find((assetPath) => {
        return assetPath.includes(".js");
      });
      const htmlAsset = Object.keys(compilation.assets).find((assetPath) => {
        return assetPath.includes(".html");
      });
      if (!jsAssets || !htmlAsset) return;
      // 设置生成js的路径
      const jsPathArr = jsAssets?.split("/") ?? [];
      if (jsPathArr.length === 0) return;
      jsPathArr[jsPathArr.length - 1] = `build-info-${new Date().getTime().toString().slice(7)}.js`;
      const jsFilePath = jsPathArr.join("/");
      // 更改body内的内容
      let htmlContent = compilation.assets?.[htmlAsset]?.source();
      if (!htmlContent) return;
      let bodyContent = htmlContent.match(
        /(?<=<body>)[\s\S]*(?=<\/body>)/gim
      )?.[0];
      if (!bodyContent) return;
      bodyContent += `<script src="${compiler.options.output.publicPath}${jsFilePath}"></script>`;
      const newBodyContent = htmlContent.replace(
        /(?<=<body>)[\s\S]*(?=<\/body>)/gim,
        bodyContent
      );
      // 更改输出资源
      compilation.assets[htmlAsset] = {
        source() {
          return newBodyContent;
        },
        size() {
          return newBodyContent.length;
        },
      };
      let content = this.jsContent();
      compilation.assets[jsFilePath] = {
        source() {
          return content;
        },
        size() {
          return content.length;
        },
      };
    });
  }
}

module.exports = buildInfoPlugin;
